#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stddef.h>

// for linux
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
// printf常用的格式：
// %d 输出int
// %u 输出unsigned int
// %ld 输出long
// %lu 输出unsigned long
// %x 输出16进制。
// %c 输出字符。ASCII可显示字符。
// %f 打印浮点型。
// %.3f 打印浮点型,保留3位小数。
// %s 打印字符串。ASCII码或utf8或gbk等。出现乱码，说明终端配置的编码格式和程序编码格式不一致。在code工具可以查看和修改本文件的编码格式。
// \\ 打印反斜杠
// \n 换行。
// \r 回车。linux用\n就能换行了，但window需要\r\n
// \" 打印"
// %5d 右对齐打印int
// %05d 右对其打印int，不足5字节，补0。
// %20s 右对齐打印字符串，不足20字节，补空格。
// %-20s 左对齐打印字符串，不足20字节，补空格。
// %*s, size, str.指定长度打印，避免访问超界。
// %%打印%

// scanf格式类似。
// scanf("%[^\n]")一些特殊用法。
// scanf("%[a-z]", a)//%[a-z]匹配a-z任意数据,到字符串, 直到没有匹配到a-z的字符。
// scanf("%[^\n]", a)//%[^\n]匹配a-z任意数据,到字符串，直到\n。^不匹配的意思
// scanf("%*[^A]%s", a)//%*[^A]丢弃A字符之前的字符串， 从A后的字符串数输出到a。
// scanf("%10s", a)//指定长度输入到字符串a。避免崩溃。

// sprintf/fprintf与printf格式一样。
// sscanf/fscanf与scanf格式一样。

enum logLevelEnum
{
    logLevelFatal = 0,
    logLevelError,
    logLevelWarn,
    logLevelInform,
    logLevelDebug,
    logLevelTrace,
};
#define MY_LOG_LEVEL_FLAG logLevelTrace

#define printf_common(lev, fmt, lprt, ...)                                                                             \
    do                                                                                                                 \
    {                                                                                                                  \
        if (lev <= MY_LOG_LEVEL_FLAG)                                                                                  \
        {                                                                                                              \
            struct timeval tnow;                                                                                       \
            struct tm *tmnow;                                                                                          \
            gettimeofday(&tnow, NULL);                                                                                 \
            tmnow = localtime(&tnow.tv_sec);                                                                           \
            printf("[%d-%02d-%02d %02d:%02d:%02d.%03d][%s][%s,%d]" fmt "\n", tmnow->tm_year + 1900, tmnow->tm_mon + 1, \
                   tmnow->tm_mday, tmnow->tm_hour, tmnow->tm_min, tmnow->tm_sec, (int)tnow.tv_usec / 1000 % 1000,      \
                   lprt, __FILE__, __LINE__, ##__VA_ARGS__);                                                           \
        }                                                                                                              \
    } while (0);
#define printffatal(fmt, ...) printf_common(logLevelFatal, fmt, "fat", ##__VA_ARGS__)
#define printerror(fmt, ...) printf_common(logLevelError, fmt, "err", ##__VA_ARGS__)
#define printwarn(fmt, ...) printf_common(logLevelWarn, fmt, "war", ##__VA_ARGS__)
#define printinform(fmt, ...) printf_common(logLevelInform, fmt, "inf", ##__VA_ARGS__)
#define printdebug(fmt, ...) printf_common(logLevelDebug, fmt, "dbg", ##__VA_ARGS__)
#define printtrace(fmt, ...) printf_common(logLevelTrace, fmt, "tra", ##__VA_ARGS__)

// 这个方式已经被废弃了！在设计过程中不断设想更好的方式。

int main(int argc, char **argv)
{
    int tmpval = 5879;
    const char *tmpstr = "myname";
    // 这里使用新方式打印。简化输出格式。
    printdebug("hello world!");
    printdebug("%10d", tmpval);
    printdebug("%010d", tmpval);
    printdebug("%20s", tmpstr);
    printdebug("%-20s", tmpstr);
    printdebug("%.*s", 3, tmpstr);
    // 因为返回类型是int，因此return 整数;
    return 1;
}
